//歯科レセプト 歯表示領域操作プラグイン by NDSS fushimi
////////////////////////////////////////////////////////////
// 汎用クロ―ジャ回避オブジェクト

// createLeakFreeeClosureを直接グローバルに配置すると
// 解放時に他の処理で作られたクロ―ジャも消えてしまう。
// そのため、各処理単位でオブジェクトを作成し、操作は
// そのオブジェクト単位に行う。

testObj2Handle = 0;// これはグローバルに管理する。書き換えないこと。
var testObj2 = function(){
	testObj2Handle ++;
	
	testObj2[testObj2Handle] = function() 
	{
		var TotalFuncCount = 0;
		var myHandle = testObj2Handle;// 親であるtestObj2を引くために使う。不要？
		
		var outFunc = function(_closure)
		{
			var count = TotalFuncCount ++; // 登録したクロ―ジャを引くために使う
			outFunc[count] = _closure;
			_closure = null;
			
			// このreturnをbindさせる。
			return function() { return outFunc[count].apply(this, arguments);};
		}
		
		this.closure = function(_closure)
		{
			return outFunc(_closure);
		}
		
		this.release = function()
		{// 全関数の開放
			for(var i = 0;i <= TotalFuncCount; i++)
			{	// ToDo: ここは nullにする。エラーを出したくないなら、 function(){ };にする。
				//outFunc[i] = function(){alert("myHandle = ".concat(myHandle).concat(" の関連処理は消えてます")) };
				outFunc[i] = null;
			}
			TotalFuncCount = 0;
			
		}
	};
	
	return testObj2[testObj2Handle].apply(this, arguments);
};
var f2 = new testObj2;// クロージャ回避用オブジェクト
// クロージャ回避オブジェクトここまで
//////////////////////////////////////////////////////

;(function($) {

$.fn.extend({
	buieditor: function(options) {
	
		options = $.extend({}, {
			autoAdjust: false,			//画像サイズの自動調整を行うか。falseの場合でも、初期表示時には自動調整が行われる
			drawDelay: 1,			        //画像サイズの判別を、画面描画と同期せずに、ディレイをかける場合に指定
			readOnly: true					//表示モードかどうか（デフォルトで表示のみ。部位入力など、編集可能とする場合は、falseにする）
		}, options);
	
		return this.each(function() {
			new $.DentalStatusHandler(this,options);
		});
		
	},
	buiSelect: function(index, status, type, part, option){
		return this.trigger("buiSelect", [index, status, type, part, option]);
	},
	buiToggleSelect: function(index, type, status,  part){
		return this.trigger("buiToggleSelect", [index, status, type, part]);
	},
	buiUpdate: function(index, status, type, part){
		return this.trigger("buiUpdate", [index, status, type, part]);
	},
	buiBatchSelect: function(indexArray, type, status){
		return this.trigger("buiBatchSelect", [indexArray, type, status]);
	},
	buiAdd: function(index, status, type, part){
		return this.trigger("buiInsert", [index, status, type, part]);
	},
	buiAddShishiki: function(shishiki){
		return this.trigger("buiAddShishiki", [shishiki]);
	},
	buiResetStatus: function(status){
		return this.trigger("buiResetStatus", [status]);
	},
	buiSetShiga: function(index, type, shiga){
		return this.trigger("buiSetShiga", [index, type, shiga]);
	},
	buiUnSetShiga: function(index, type){
		return this.trigger("buiUnSetShiga", [index, type]);
	},
	buiAddClassShishiki: function(shishiki, name){
		return this.trigger("buiAddClassShishiki", [shishiki, name]);
	},
	buiUnSelect: function(index){
		return this.trigger("buiUnSelect", [index]);
	},
	buiUnSelectAll: function(){
		return this.trigger("buiUnSelectAll");
	},
	buiSeliarize: function(){
		var data = new Array();
		this.trigger("buiSeliarize", [data]);
		return data;
	},
	buiBindData: function(data){
		return this.trigger("buiBindData", [data]);
	},
	buiSetBuMode: function(data){
		return this.trigger("buiSetBuMode");
	},
	buiUnsetBuMode: function(data){
		return this.trigger("buiUnsetBuMode");
	},
	buiGetBuiInfo: function(index){
		var info = new Array();
		this.trigger("buiGetBuiInfo", [index, info]);
		return info;
	},
	buiAdjustImage: function(){
		this.trigger("buiAdjustImage");
	},
	//設定された歯式が「部」を含むかどうかを取得する
	//プラグイン適用時の引数で、drawDelayを"1"以上に設定していた場合、
	//正常に取得できないので注意。
	//使用する場合は、"drawDelay: 0"を必ず指定する必要がある。
	buiIsBuMode: function(){
		//パフォーマンス改善改修 start
		//データ名 "metadata" はmetadataプラグインと名称が重複するので、変更
		//var metadata = $.data($(this).find("li.selected:first").get(0), "metadata");
	
		var metadata = $.data($(this).find("li.selected:first").get(0), "blindData");
		
		if(!metadata || !metadata.shishiki[0]){
			return false;
		}else{
			return metadata.shishiki[0].status == 1 ? true : false;
		}
		//パフォーマンス改善改修 end
	},
	buiIsEmpty: function(){
		return $(this).find("li.selected:first").size() == 0;
	},
	deActivate:function(){
		// kikuyakzy: deActivate追加、クロージャを開放
		f2.release();
	}
});

$.DentalStatusHandler = function(targetDiv,options) {
	
	//------------------------------------------------------
	//初期化処理
	//------------------------------------------------------
	
	//[定数定義]
	//クラス名定数
	var CLASSES = {
		DISPLAY_AREA:	"buicontrol_displayarea",
		LEFT:   		"left",
		RIGHT:  		"right",
		TOP:    		"top",
		BOTTOM: 		"bottom",
		COL:			"col",
		TOOTH:			"tooth",
		ACTIVE:			"active",
		SELECTED:		"selected",
		DATA:			"data",
		STATUS:			"status",
		NYUSHI:			"nyushi",
		EIKYUSHI:		"eikyushi"
	}
	
	
	
	//エリアコード・歯種別毎に、歯式への変換を定義
	//乳歯と永久歯で、同じ箇所でもコードが異なっている為、
	//エリア番号と歯の種別で判断する必要が有る
	//例）
	//エリア：1(右上) 
	//歯種別：1(乳歯)
	// ⇒歯式では"105"
	var AREA_TO_SHISHIKI_MAP = {
		"1":	{"1":"105", "2":"101" },
		"2":	{"1":"106", "2":"102" },
		"3":	{"1":"108", "2":"104" },
		"4":	{"1":"107", "2":"103" }
	}
	
	
	//歯式の歯式から、エリア番号と歯の種別を判別する
	var SHISHIKI_TO_AREA_MAP = {
		"101": {area: "1", type: "2"},
		"102": {area: "2", type: "2"},
		"103": {area: "4", type: "2"},
		"104": {area: "3", type: "2"},
		"105": {area: "1", type: "1"},
		"106": {area: "2", type: "1"},
		"107": {area: "4", type: "1"},
		"108": {area: "3", type: "1"}
	}
	
	
	//エリアコード
	//歯式ではなく、あくまで表示域の位置を定義
	//歯式の記述は、このコードと、歯種別（乳歯 or 永久歯）で決定される
	var AREA_CODE = {
		LEFT_TOP:		"1",
		RIGHT_TOP:		"2",
		LEFT_BOTTOM:	"3",
		RIGHT_BOTTOM:	"4"
	}
	
	//状態コード
	var STATUS_CODE = {
		CURRENT:	"0",
		BU:			"1",
		KESSON:		"2",
		SHIDAI:		"3",
		BSHIDAI:	"5",
		KINSHIN:	"8"
	}

	//乳歯 or 永久歯
	var TOOTH_TYPE = {
		NYUSHI:		"1",
		EIKYUSHI:	"2"
	}
	
	//画像サイズの定義
	var IMAGE_SIZE = {
		//大・中・小 イメージの基本サイズ
		BASE_SIZE: {
								LARGE: { SIZE : 8, CLASS_NAME : "image_L"},
								//MEDIUM: { SIZE : 5, CLASS_NAME : "image_M"},
								SMALL: { SIZE : 3, CLASS_NAME : "image_S"}
							},
		//各状態コードにおける、画像サイズの増分値を指定
		DELTA: { 
						"3": 4,
						"5": 7,
						"8": 0,
						"0": 0,
						"1": 0,
						"2": 0
		}
	}
	

	//パフォーマンス改善改修第二段 start
	//要素を動的に生成すると、IEでメモリーリークが発生する
	//動的生成は止めて、HTMLを直書き

	//要素の位置情報（エリアコード(1～4)と、番号(1～8)）を保持
	//パフォーマンス改善改修 start
	//エリア情報はmetadataで保持するように変更
	
	//var AREA_INFO = "area_info";
	
	//パフォーマンス改善改修 end
	
	//[変数定義]
	//操作対象のdivをjqueryオブジェクトで取得
	//var $div = $(div).addClass(CLASSES.DISPLAY_AREA);
	//
//	//歯式と部を囲むDIV
//	var $buiDiv = $("<div></div>").appendTo($(targetDiv));
//
//	//歯式表示部分のdiv
//	var $shishikiDiv = $("<div></div>").addClass(CLASSES.DISPLAY_AREA).appendTo($buiDiv);
//	
//	//部のDIV
//	var $buDiv = $("<div></div>").addClass("buicontrol_buarea")
//							//.append($("<span/>").text("部").css("display","none"))
//							.append($("<span></span>").text("部"))
//							.appendTo($buiDiv);
//
// 	//パフォーマンス改善改修 start
// 	//各歯を現すliタグは、ループで作るのではなく、あらかじめ用意しておく
// 	
//	//歯の構成要素のli
//	//右側の歯		
//	var $toothElem_right_top =$("<ul id='right_top'>"
//									+ "<li class=\"tooth1 {no: '1'}\"></li>"
//									+ "<li class=\"tooth2 {no: '2'}\"></li>"
//									+ "<li class=\"tooth3 {no: '3'}\"></li>"
//									+ "<li class=\"tooth4 {no: '4'}\"></li>"
//									+ "<li class=\"tooth5 {no: '5'}\"></li>"
//									+ "<li class=\"tooth6 {no: '6'}\"></li>"
//									+ "<li class=\"tooth7 {no: '7'}\"></li>"
//									+ "<li class=\"tooth8 {no: '8'}\"></li>"
//							+"</ul>");
//	//左側の歯						
//	var $toothElem_left_top = $("<ul id='left_top'>"
//									+ "<li class=\"tooth8 {no: '8'}\"></li>"
//									+ "<li class=\"tooth7 {no: '7'}\"></li>"
//									+ "<li class=\"tooth6 {no: '6'}\"></li>"
//									+ "<li class=\"tooth5 {no: '5'}\"></li>"
//									+ "<li class=\"tooth4 {no: '4'}\"></li>"
//									+ "<li class=\"tooth3 {no: '3'}\"></li>"
//									+ "<li class=\"tooth2 {no: '2'}\"></li>"
//									+ "<li class=\"tooth1 {no: '1'}\"></li>"
//							+"</ul>");
//							
//	var $toothElem_right_bottom =$("<ul id='right_bottom'>"
//									+ "<li class=\"tooth1 {no: '1'}\"></li>"
//									+ "<li class=\"tooth2 {no: '2'}\"></li>"
//									+ "<li class=\"tooth3 {no: '3'}\"></li>"
//									+ "<li class=\"tooth4 {no: '4'}\"></li>"
//									+ "<li class=\"tooth5 {no: '5'}\"></li>"
//									+ "<li class=\"tooth6 {no: '6'}\"></li>"
//									+ "<li class=\"tooth7 {no: '7'}\"></li>"
//									+ "<li class=\"tooth8 {no: '8'}\"></li>"
//							+"</ul>");
//	//左側の歯						
//	var $toothElem_left_bottom = $("<ul id='left_bottom'>"
//									+ "<li class=\"tooth8 {no: '8'}\"></li>"
//									+ "<li class=\"tooth7 {no: '7'}\"></li>"
//									+ "<li class=\"tooth6 {no: '6'}\"></li>"
//									+ "<li class=\"tooth5 {no: '5'}\"></li>"
//									+ "<li class=\"tooth4 {no: '4'}\"></li>"
//									+ "<li class=\"tooth3 {no: '3'}\"></li>"
//									+ "<li class=\"tooth2 {no: '2'}\"></li>"
//									+ "<li class=\"tooth1 {no: '1'}\"></li>"
//							+"</ul>");
//
//	//表示エリアのul要素
//	//var $leftTop = $("<ul/>").addClass(CLASSES.LEFT).addClass(CLASSES.TOP);
//	//var $leftTop = $toothElem.clone().addClass(CLASSES.LEFT).addClass(CLASSES.TOP);
//	$("<div></div>").addClass("buidivision").addClass("toothList_LeftTop").attr("id", "left_top")
//		.append($toothElem_left_top.addClass(CLASSES.LEFT).addClass(CLASSES.TOP).addClass("{area:" + AREA_CODE.LEFT_TOP + "}"))
//		.appendTo($shishikiDiv);
//	
//	//var $rightTop = $("<ul/>").addClass(CLASSES.RIGHT).addClass(CLASSES.TOP);
//	//$("<div/>").addClass("buidivision").addClass("toothList_RightTop").append($rightTop).appendTo($shishikiDiv);
//	$("<div></div>").addClass("buidivision").addClass("toothList_RightTop").attr("id", "right_top")
//		.append($toothElem_right_top.addClass(CLASSES.RIGHT).addClass(CLASSES.TOP).addClass("{area:" + AREA_CODE.RIGHT_TOP + "}"))
//		.appendTo($shishikiDiv);
//	
//	//var $leftBottom = $("<ul/>").addClass(CLASSES.LEFT).addClass(CLASSES.BOTTOM);
//	//$("<div/>").addClass("buidivision").addClass("toothList_LeftBottom").append($leftBottom).appendTo($shishikiDiv);
//	$("<div></div>").addClass("buidivision").addClass("toothList_LeftBottom").attr("id", "left_bottom")
//		.append($toothElem_left_bottom.addClass(CLASSES.LEFT).addClass(CLASSES.BOTTOM).addClass("{area:" + AREA_CODE.LEFT_BOTTOM + "}"))
//		.appendTo($shishikiDiv);
//	
//	//var $rightBottom = $("<ul/>").addClass(CLASSES.RIGHT).addClass(CLASSES.BOTTOM);
//	//$("<div/>").addClass("buidivision").addClass("toothList_RightBottom").append($rightBottom).appendTo($shishikiDiv);
//	$("<div></div>").addClass("buidivision").addClass("toothList_RightBottom").attr("id", "right_bottom")
//		.append($toothElem_right_bottom.addClass(CLASSES.RIGHT).addClass(CLASSES.BOTTOM).addClass("{area:" + AREA_CODE.RIGHT_BOTTOM + "}"))
//		.appendTo($shishikiDiv);
	
	
	
//		//1行目左側(8～1)の要素を生成する
//	for (var i=0; i < 8; i++) {
//		var $li = $("<li/>")
//						//.addClass(CLASSES.COL + i)
//						.addClass(CLASSES.TOOTH + (8 - i))
//						.appendTo($leftTop);
//		//エリアコードを設定
//		$.data($li.get(0), AREA_INFO, {"area":AREA_CODE.LEFT_TOP, "no": 8 - i});
//	}
//
//	//1行目右側(1～8)の要素を生成する
//	for (var i=0; i < 8; i++) {
//		var $li = $("<li/>")
//					//.addClass(CLASSES.COL + i )
//					.addClass(CLASSES.TOOTH + (i + 1))
//					.appendTo($rightTop);
//		$.data($li.get(0), AREA_INFO, {"area":AREA_CODE.RIGHT_TOP, "no":i + 1});
//	}
//
//	//2行目左側(8～1)の要素を生成する
//	for (var i=0; i < 8; i++) {
//		var $li = $("<li/>")
//					//.addClass(CLASSES.COL + i)
//					.addClass(CLASSES.TOOTH + (8 - i))
//					.appendTo($leftBottom);
//		$.data($li.get(0), AREA_INFO, {"area":AREA_CODE.LEFT_BOTTOM, "no": 8 - i});
//	}
//	
//	//2行目右側(1～8)の要素を生成する
//	for (var i=0; i < 8; i++) {
//		var $li = $("<li/>")
//					//.addClass(CLASSES.COL + i )
//					.addClass(CLASSES.TOOTH + (i + 1))
//					.appendTo($rightBottom);
//		$.data($li.get(0), AREA_INFO, {"area":AREA_CODE.RIGHT_BOTTOM, "no": i + 1});
//	}

	//パフォーマンス改善改修 end
	//$(targetDiv).append("<div  class='buidiv'/>");
	$(targetDiv).append("<div  class='buidiv'/>").find("div.buidiv").html("<div class=\"buicontrol_displayarea\"><div class=\"buidivision toothList_LeftTop\" id=\"left_top\"><ul id=\"left_top\" class=\"left top {area:1}\"><li class=\"tooth8 {no: '8'}\"/><li class=\"tooth7 {no: '7'}\"/><li class=\"tooth6 {no: '6'}\"/><li class=\"tooth5 {no: '5'}\"/><li class=\"tooth4 {no: '4'}\"/><li class=\"tooth3 {no: '3'}\"/><li class=\"tooth2 {no: '2'}\"/><li class=\"tooth1 {no: '1'}\"/></ul></div><div class=\"buidivision toothList_RightTop\" id=\"right_top\"><ul id=\"right_top\" class=\"right top {area:2}\"><li class=\"tooth1 {no: '1'}\"/><li class=\"tooth2 {no: '2'}\"/><li class=\"tooth3 {no: '3'}\"/><li class=\"tooth4 {no: '4'}\"/><li class=\"tooth5 {no: '5'}\"/><li class=\"tooth6 {no: '6'}\"/><li class=\"tooth7 {no: '7'}\"/><li class=\"tooth8 {no: '8'}\"/></ul></div><div class=\"buidivision toothList_LeftBottom\" id=\"left_bottom\"><ul id=\"left_bottom\" class=\"left bottom {area:3}\"><li class=\"tooth8 {no: '8'}\"/><li class=\"tooth7 {no: '7'}\"/><li class=\"tooth6 {no: '6'}\"/><li class=\"tooth5 {no: '5'}\"/><li class=\"tooth4 {no: '4'}\"/><li class=\"tooth3 {no: '3'}\"/><li class=\"tooth2 {no: '2'}\"/><li class=\"tooth1 {no: '1'}\"/></ul></div><div class=\"buidivision toothList_RightBottom\" id=\"right_bottom\"><ul id=\"right_bottom\" class=\"right bottom {area:4}\"><li class=\"tooth1 {no: '1'}\"/><li class=\"tooth2 {no: '2'}\"/><li class=\"tooth3 {no: '3'}\"/><li class=\"tooth4 {no: '4'}\"/><li class=\"tooth5 {no: '5'}\"/><li class=\"tooth6 {no: '6'}\"/><li class=\"tooth7 {no: '7'}\"/><li class=\"tooth8 {no: '8'}\"/></ul></div></div><div class=\"buicontrol_buarea\"><span>部</span></div>");
	//$(targetDiv).find("div.buidiv").html("<div><div class=\"buicontrol_displayarea\"><div class=\"buidivision toothList_LeftTop\" id=\"left_top\"><ul id=\"left_top\" class=\"left top {area:1}\"><li class=\"tooth8 {no: '8'}\"/><li class=\"tooth7 {no: '7'}\"/><li class=\"tooth6 {no: '6'}\"/><li class=\"tooth5 {no: '5'}\"/><li class=\"tooth4 {no: '4'}\"/><li class=\"tooth3 {no: '3'}\"/><li class=\"tooth2 {no: '2'}\"/><li class=\"tooth1 {no: '1'}\"/></ul></div><div class=\"buidivision toothList_RightTop\" id=\"right_top\"><ul id=\"right_top\" class=\"right top {area:2}\"><li class=\"tooth1 {no: '1'}\"/><li class=\"tooth2 {no: '2'}\"/><li class=\"tooth3 {no: '3'}\"/><li class=\"tooth4 {no: '4'}\"/><li class=\"tooth5 {no: '5'}\"/><li class=\"tooth6 {no: '6'}\"/><li class=\"tooth7 {no: '7'}\"/><li class=\"tooth8 {no: '8'}\"/></ul></div><div class=\"buidivision toothList_LeftBottom\" id=\"left_bottom\"><ul id=\"left_bottom\" class=\"left bottom {area:3}\"><li class=\"tooth8 {no: '8'}\"/><li class=\"tooth7 {no: '7'}\"/><li class=\"tooth6 {no: '6'}\"/><li class=\"tooth5 {no: '5'}\"/><li class=\"tooth4 {no: '4'}\"/><li class=\"tooth3 {no: '3'}\"/><li class=\"tooth2 {no: '2'}\"/><li class=\"tooth1 {no: '1'}\"/></ul></div><div class=\"buidivision toothList_RightBottom\" id=\"right_bottom\"><ul id=\"right_bottom\" class=\"right bottom {area:4}\"><li class=\"tooth1 {no: '1'}\"/><li class=\"tooth2 {no: '2'}\"/><li class=\"tooth3 {no: '3'}\"/><li class=\"tooth4 {no: '4'}\"/><li class=\"tooth5 {no: '5'}\"/><li class=\"tooth6 {no: '6'}\"/><li class=\"tooth7 {no: '7'}\"/><li class=\"tooth8 {no: '8'}\"/></ul></div></div><div class=\"buicontrol_buarea\"><span>部</span></div></div>");
	
	//li要素の集合を取得
	//var $lis =  $shishikiDiv.find("li");
	var $lis =  $(targetDiv).find("li");
	
		//パフォーマンス改善改修第二段 end
	
	
	//パフォーマンス改善改修 start
	//内部保持データの一括初期化は行わず、必要になった時点で初期化するように修正
	
	//内部データの初期化
	//$lis.attr("metadata", $.toJSON({area_info:{area: "1", no: "1"}, kokunai: [{type: "1", shiga: "0"},{type: "2", shiga: "0"}], shishiki: []}));
	//$lis.attr("metadata", $.toJSON({no: "1"}));
	//$lis.each(function(){
	//	setBlindData(this,{kokunai: [{type: "1", shiga: "0"},{type: "2", shiga: "0"}], shishiki: []} );
	//});
	//パフォーマンス改善改修 end
	
	
	//初期表示データの展開処理
	//表示対象データが存在した場合は、それをデフォルト値として表示する
	var defaultData = $(targetDiv).find(":input:first").val();
	
	
	if(defaultData){
		//console.log("[初期表示データ]" + defaultData)
		//setTimeout("bindData(defaultData)", 100);
		
		//パフォーマンス改善改修 start
		//データの紐付けとイメージサイズの算出は後回しにする
		
		//部モードが有効だった場合、部表示を有効にする
//		bindData(defaultData);
//		var metadata = getBlindData($(targetDiv).find("li.selected:first"));
//		if(metadata.shishiki[0].status == 1){
//			setBuMode();
//		}
		
		if(options.drawDelay > 0){
			setTimeout(function(){
				bindData(defaultData);
				var metadata = getBlindData($(targetDiv).find("li.selected:first"));
				if(metadata.shishiki[0].status == 1){
					setBuMode();
				}
			},options.drawDelay);
		}else{
				bindData(defaultData);
				var metadata = getBlindData($(targetDiv).find("li.selected:first"));
				if(metadata.shishiki[0].status == 1){
					setBuMode();
				}
		}
		
		//パフォーマンス改善改修 end
	}
	
	//------------------------------------------------------
	//関数定義（イベント経由で呼び出す）
	//------------------------------------------------------
	//内部データを取得する
	function getBlindData(li){
	
		//パフォーマンス改善改修 start
		//非表示データは、$.data で紐付けする。
		//データが存在しない場合は、空のオブジェクトを返却する
		
		//return $(li).metadata( {type: 'attr', name: 'metadata'});
		var metadata = $.data($(li).get(0), "blindData");
		
		if(!metadata){
			metadata = {};
		}
		
		return metadata;
		//パフォーマンス改善改修 end
	}
	
	//内部データを設定する
	function setBlindData(li, data){
		//パフォーマンス改善改修 start
		//非表示データは、$.data で紐付けする。
		$.data($(li).get(0), "blindData", data);
		//$(li).attr("metadata", $.toJSON(data));
		//パフォーマンス改善改修 end
	}
	
	//パフォーマンス改善改修 start
	//li 要素に紐付けた metadata から位置情報を取得する
	
	//li要素に紐付けられた場所情報を取得する
	function getAreaInfo(li){
		return {area: $(li).parent().metadata().area, no: $(li).metadata().no};
	}
	//パフォーマンス改善改修 end
	
	//「部」モードを有効にする
	function setBuMode(){
		$(targetDiv).find(".buidiv").addClass("bu_active");
	}
	
	//「部」モードを解除する
	function unsetBuMode(){
		$(targetDiv).find(".buidiv").removeClass("bu_active");
	}
	
	
	//前回の画像サイズを覚えておく
	var previousClass = undefined;
	
	//最適な画像サイズを算出し、設定する
	function adjustImage(){
	
		//各エリアの、選択済み要素数と、差分値の合計を保持
		var sizeArray = new Array(); 
		
		// 故障対応:SIG1_3216 start
		//前回の画像サイズを覚えておく
		if($lis.find("div").hasClass("image_S")){
		    previousClass = IMAGE_SIZE.BASE_SIZE.SMALL.CLASS_NAME;
		}
		// 故障対応:SIG1_3216 end
		
		//一番多く選択されているエリアを探し、選択数を確保
		$(targetDiv).find("ul").each(function(){
			
			//合計サイズのテンポラリ
			var totalDelta = 0;
			//表示対象要素数
			var count = $(this).find("div").size();
			
			//選択済みの要素情報から、差分値を取得する
			$(this).find("li").each(function(){
				//var metadata = $(this).metadata({'type':'attr','name':'metadata'});
				var metadata = getBlindData(this)
				
				//歯式が設定されていた場合はサイズ算出
				if(metadata.shishiki){
					$.each(metadata.shishiki, function(i, val){
						totalDelta += IMAGE_SIZE.DELTA[val.status];
					});
				}
			});
			
			//console.log("[選択済み要素]count:%s delta:%s", count, totalDelta);
			
			sizeArray.push({"count": count, "totalDelta": totalDelta});
			
		});
		
		//表示領域の幅を取得
		var width = $(targetDiv).find("div.buidivision:first").innerWidth();
		
		//console.log("[表示領域サイズ]width:%s", width);
		
		//算出した横幅の基準値
		//どう頑張っても入りきらない場合に備え、デフォルトで small に指定
		var baseWidth = IMAGE_SIZE.BASE_SIZE.SMALL.SIZE;
		var imageClass = IMAGE_SIZE.BASE_SIZE.SMALL.CLASS_NAME;
		
		//サイズが確定hしたかどうかの判定
		//ループの終了条件
		var sizeOver = false;
		
		//パフォーマンス改善改修 start
		//画像サイズは2パターンなので、
		//「大サイズで表示可能か」のみを判定するように修正
		
		//表示可能な最大サイズを算出する
		//大きいほうから順に実際に計算してみて、はみ出る箇所が無いものを調べる
		//ロジック的に無駄が多い・・・
//		$.each(IMAGE_SIZE.BASE_SIZE, function(key, image){
//			
//			 sizeOver = false;
//			
//			$.each(sizeArray, function(i, obj){
//				//サイズがオーバーしていた場合は抜ける
//				if(image.SIZE*obj.count + obj.totalDelta > width){
//					//console.log("[サイズオーバー]size:%s", size*obj.count + obj.totalDelta);
//					sizeOver = true;
//					return false;
//				}
//			});
//			
//			//サイズが確定していた場合はそのサイズをセット
//			if(!sizeOver){
//				baseWidth = image.SIZE;
//				imageClass = image.CLASS_NAME;
//				return false;
//			}
//			
//		});
		
		//大きいサイズで表示可能かを計算する
		var baseSize_Large = IMAGE_SIZE.BASE_SIZE.LARGE;
		var baseSize_small = IMAGE_SIZE.BASE_SIZE.SMALL;
		
		//各エリアのついて、大サイズ画像で表示可能かを計算
		$.each(sizeArray, function(i, obj){
			//サイズがオーバーしていた場合は抜ける
			if(baseSize_Large.SIZE*obj.count + obj.totalDelta > width){
				sizeOver = true;
				return false;
			}
		});
		
		//サイズが確定していた場合はそのサイズをセット
		if(!sizeOver){
			baseWidth = baseSize_Large.SIZE;
			imageClass = baseSize_Large.CLASS_NAME;
		}else{
			baseWidth = baseSize_small.SIZE;
			imageClass = baseSize_small.CLASS_NAME;
		}
		
		//パフォーマンス改善改修 		
		
		//console.log("[選択サイズ]size:%s", baseWidth);
		
		//表示領域のサイズ設定classを、算出したclassに設定する
		
		//表示要素のサイズを、算出したサイズに設定する
		$lis.filter(".selected").each(function(i, li){
			//var shishiki = $(this).metadata({'type':'attr','name':'metadata'}).shishiki;
			var shishiki = getBlindData(this).shishiki;
			
			$.each(shishiki, function(j, obj){
				var imageWidth = baseWidth + IMAGE_SIZE.DELTA[obj.status];
				
				if(previousClass){
					$(li).find("div").eq(j).removeClass(previousClass)
				}
				
				$(li).find("div").eq(j)
						.removeAttr("style").attr("style", "width: " + imageWidth + "px;")
						.addClass(imageClass);
			});
		});
		
		//前回のクラスを保持
		previousClass = imageClass;
		
	}
	
	//指定された要素が欠損歯として選択されているかを取得する
	function isKesson(li){
		var isKesson = false;
		
		//対象が欠損歯かどうかをチェック
		//$.each(li.metadata({'type':'attr','name':'metadata'}).kokunai, function(){
		$.each(getBlindData(li).kokunai, function(){
			if(this.shiga== "2" ){
				isKesson = true;
				//ここのreturn はループ脱出用(break)
				return false;
			}
		});
		
		return isKesson;
	}
//	function isKesson(li, type){
//		var isKesson = false;
//		
//		//対象が欠損歯かどうかをチェック
//		//$.each(li.metadata({'type':'attr','name':'metadata'}).kokunai, function(){
//		$.each(getBlindData(li).kokunai, function(){
//			if(this.type == type && this.shiga== "2" ){
//				isKesson = true;
//				//ここのreturn はループ脱出用(break)
//				return false;
//			}
//		});
//		
//		return isKesson;
//	}
	

	//指定したを要素を選択状態にします
	//
	//指定した要素がすでに選択されていた場合の動作は
	//・"force"が false の場合（デフォルト）
	//   何も行わない
	//・"force"が true の場合
	//  指定したモードで上書きする
	
	//li:		選択対象のli要素
	//status:	選択対象の状態コード(0:現在歯 1:部 2:欠損歯 3:支台歯 5:なんちゃら支台歯 8:部近心隙)
	//type:		選択対象が永久歯か乳歯か(1:乳歯 2:永久歯)
	//part:		部分コード（0:指定無し 7:遠心根 8:近心根）
	//force:	上書き設定（true:上書きする false:上書きしない）
	function select(li, status, type, part, option){
	
		//オプションを初期化
		option = $.extend({},
						 {
							force: false,
							shigaSensitive: false
						},
						option);
	
		//上書きモードの場合は問答無用でいったん選択解除する
		if(option.force){
			unSelect(li);
		}
		
		if(option.shigaSensitive){
			if(isKesson(li)){
				return;
			}
		}

		//選択されていなかった場合のみ、選択状態にし、
		//指定されたステータスを設定する
		if(li.hasClass(CLASSES.SELECTED) == false){
			li.addClass(CLASSES.SELECTED);
			addBuiElement(li, status, type, part);
		}
	};
	
	//要素が選択されているかを取得
	function isSelected(li){
		return li.hasClass(CLASSES.SELECTED);
	}
	
	
	function selectByShishiki(shishiki, force){
		var bui = createBui(shishiki);
		select($lis.eq(bui.index), bui.status, bui.type, bui.part, {force: true});
	}
	
	//指定したを要素の選択状態を解除します
	function unSelect(li, shigaSensitive ){
	
		//デフォルトでは、歯牙状態を考慮し、欠損歯の場合は無視する
		if(shigaSensitive == undefined){
			shigaSensitive = true;
		}
	
		if(li.hasClass(CLASSES.SELECTED)){
			
			//選択を解除し、歯要素を削除する
			li.removeClass(CLASSES.SELECTED).empty();
			
			//metadataに設定した歯式の情報も削除する
			//var metadata = li.metadata({'type':'attr','name':'metadata'});
			var metadata = getBlindData(li);
			metadata.shishiki = new Array();
			//li.attr("metadata", $.toJSON(metadata));
			setBlindData(li, metadata);

		}
	};

	//指定した要素の表示/非表示を切り替えます
	//
	//  非表示だった場合 ⇒ 指定したモードで選択状態にする
	//  表示中だった場合 ⇒ 非表示にする
	//
	function toggleSelect(li, status, type, part){

		//非表示だった場合は表示する
		if(li.hasClass(CLASSES.SELECTED) == false){
			select(li, status, type, part);
		}else{
			unSelect(li);
		}
	};
	
	//指定した要素が選択状態だった場合のみ、上書きする
	function update(li, status, type, part){
		//非表示だった場合は表示する
		if(li.hasClass(CLASSES.SELECTED)){
			select(li, status, type, part, {force: true});
		}
	}
	
	//対象のindexを配列で指定し、一括して選択する
	function batchSelect(indexArray, type, status){
		
		//対称が全て選択済みかどうかのフラグ
		var allSelected = true;
		
		//既に対象が全て選択済みかどうかを判定
		$.each(indexArray, function(i, val){
			
			if(isKesson($lis.eq(Number(this)))){
				//歯牙状態を無視して強制的に選択を解除する
				unSelect($lis.eq(Number(this)), false);
			}else if($lis.eq(Number(this)).hasClass(CLASSES.SELECTED) == false){
				allSelected = false;
				//return false;
			}
		});
		
		//対称を選択 or 選択解除
		$.each(indexArray, function(){
			if(allSelected){
				unSelect($lis.eq(Number(this)));
			}else{
				select($lis.eq(Number(this)), status ? status : "0", type, "0", {force: true, shigaSensitive: true});
			}
		});
	}
	
	//指定した要素に、値を追加する（分割歯対応のため）
	//選択されていない要素に対して実行した場合は選択状態となる
	//既に選択されていた場合は、表示を追加する
	function add(li, status, type, part){
		
		//選択済みの場合はデータを追加する
		//データが設定されていなかった場合は選択する
		if(li.hasClass(CLASSES.SELECTED)){
			addBuiElement(li, status, type, part);
		}else{
			select(li, status, type, part);
		}
	}
	
	
	function addByShishiki(shishiki){
		var bui = createBui(shishiki);
		add($lis.eq(bui.index), bui.status, bui.type, bui.part);
	}
	
	function addClassByShishiki(shishiki, className){
		var bui = createBui(shishiki);
		$lis.eq(bui.index).children().addClass(className);
	}
	
	
	//全ての歯の状態を、"0"(現在歯)に設定する
	//部分コードは"0"（部分無し）になります
	function resetStatus(status){
		$lis.filter("." + CLASSES.SELECTED).each(function(){
			//設定済みの歯式を取得する
			//var shishiki = $(this).metadata({'type':'attr','name':'metadata'}).shishiki[0].shiban + status + "0";
			var shishiki = getBlindData(this).shishiki[0].shiban + status + "0";
			//一旦削除
			unSelect($(this));
			//部状態の歯式を生成し、設定し直す
			addByShishiki(shishiki);
		});
	}
	
	
	//指定した要素に、値を追加する（分割歯対応のため）
	//選択されていない要素に対して実行した場合は選択状態となる
	//既に選択されていた場合は、表示を追加する
	function addBuiElement(li, status, type, part){

		$("<div/>").addClass(type == TOOTH_TYPE.NYUSHI ? CLASSES.NYUSHI : CLASSES.EIKYUSHI)
						.addClass(CLASSES.STATUS + status)
						.appendTo(li);
		
		//設定された歯の状態
		//var metadata = li.metadata({'type':'attr','name':'metadata'});
		var metadata = getBlindData(li);
		
		//追加対象の位置情報を取得
		//var areaInfo = $.data(li.get(0), AREA_INFO);
		areaInfo = getAreaInfo(li);
		
		//歯式が設定されていなかった場合は設定する
		if(!metadata.shishiki){
			metadata.shishiki = new Array();
		}
		
		//選択された歯の状態をmetadataとして持たせる
		metadata.shishiki.push({
							shiban: AREA_TO_SHISHIKI_MAP[areaInfo.area][type] + areaInfo.no,
							status: status,
							part: part,
							type: type
						});
						
		//li.attr("metadata", $.toJSON(metadata));
		setBlindData(li, metadata);
	}
	
	//指定した li 要素に、歯牙状態を設定する
	function setShiga(li, type, shiga){
	
		//metadataの歯牙状態を上書きして設定する
		//var metadata = li.metadata({'type':'attr','name':'metadata'});
		var metadata = getBlindData(li);
		
		//口腔内情報が未設定の場合は設定する
		if(!metadata.kokunai){
			//metadata.kokunai = new Array(2);
			metadata.kokunai = new Array({'type': '1', 'shiga': '0'},{'type': '2', 'shiga': '0'}) ;
		}
		
		$.each(metadata.kokunai, function(i, val){
			if(val.type == type){
				metadata.kokunai[i].shiga = shiga;
				return false;
			}
		});
		//li.attr("metadata", $.toJSON(metadata));
		setBlindData(li, metadata);
	}
	
//	//指定されたli要素に設定された歯牙状態を解除する
//	function unSetShiga(li, type){
//	
//		var metadata = li.metadata({'type':'attr','name':'metadata'});
//		
//		$.each(metadata.kokunai, function(i, val){
//			if(this.type == type ){
//				metadata.kokunai[i].shiga = "0";
//				return false;
//			}
//		});
//		li.attr("metadata", $.toJSON(metadata));
//	}


	//現在の設定内容を、データサーバPOST用のオブジェクトに変換します
	function seliarize(){
		
		var rightTopArray = new Array();
		var rightBottomArray = new Array();
		var leftTopArray = new Array();
		var leftBottomArray = new Array();
		
		//配列への参照を切り替えるためのテンポラリ
		var tmpArray;
		
		$lis.each(function(){
			
			if($(this).hasClass(CLASSES.SELECTED)){
				
				//li 要素に紐付けられた shishiki クラスを取得
				//var metadata = $(this).metadata({'type':'attr','name':'metadata'});
				var metadata = getBlindData(this);
				//歯式情報
				var shishiki =  metadata.shishiki;
				//口腔内情報
				var kokunai = metadata.kokunai;
				
				//部位情報
				var bui = createBui(shishiki[0].shiban + shishiki[0].status + shishiki[0].part);
			
				//処理対象の要素のエリアコードに応じて、配列の参照を切り替える
				switch(bui.area){
					case AREA_CODE.RIGHT_TOP:
						tmpArray = rightTopArray;
						break;
					
					case AREA_CODE.LEFT_TOP:
						tmpArray = leftTopArray;
						break;
						
					case AREA_CODE.LEFT_BOTTOM:
						tmpArray = leftBottomArray;
						break;
					
					case AREA_CODE.RIGHT_BOTTOM:
						tmpArray = rightBottomArray;
						break;
				}
				
				//歯牙状態として欠損歯が登録されているかどうか
				//歯牙状態が欠損歯として登録されていた場合でも、
				//歯式が"0"(現在歯)以外のものだった場合には、歯式の状態コードが優先される
				//（例）
				//歯式が①で登録され、1の歯牙状態がが欠損歯だった場合、最終的な歯式は"①"のものとなる
				var isShigaKesson = false;

				//以下の場合、欠損歯として歯式を生成する必要がある
				//・選択された歯タイプの欠損歯が登録されている場合
				$.each(kokunai, function(i, val){
					if(val.type ==  shishiki[0].type &&val.shiga == "2"){
						isShigaKesson = true;
						return false;
					}
				});
				
				//歯牙状態が欠損歯だった場合
				//・状態コードが"0"(現在歯) かつ、部分コードが"0"(指定無し)
				//の場合に、欠損歯として登録する
				
				// 故障対応:SIG1_3130 start
				//if(isShigaKesson){
				
					//歯式に設定する状態コード
					//var status = shishiki[0].status;;
					
					//if( shishiki[0].status == "0" && shishiki[0].part == "0"){
						//status = "2";
					//}
					
					//tmpArray.push(shishiki[0].shiban + status + shishiki[0].part);
					
				//}else{
					//対象配列に歯式を追加
					//$.each(shishiki, function(i, val){
						//欠損歯が指定されていた場合は、欠損歯の歯式に設定する必要がある
						//tmpArray.push(val.shiban + val.status + val.part);
					//})
				//}
				
				//対象配列に歯式を追加
				$.each(shishiki, function(i, val){

				    //の場合に、欠損歯として登録する
					// 故障対応:SIG1_3426 start 2009/10/07
					//if(isShigaKesson && shishiki[i].status == "0"){
					if(isShigaKesson){
					// 故障対応:SIG1_3426 end 2009/10/07

						//歯式に設定する状態コード
						var status = shishiki[i].status;

						if( shishiki[i].status == "0" && shishiki[i].part == "0"){
							status = "2";
						}
						
						tmpArray.push(shishiki[i].shiban + status + shishiki[i].part);
						
						// 故障対応:UTG1_T055 start 2009/10/17
						if( shishiki[i].status != "8"){
							isShigaKesson = false;
						}
						// 故障対応:UTG1_T055 end 2009/10/17
						
					}else {
						//欠損歯が指定されていた場合は、欠損歯の歯式に設定する必要がある
						// 故障対応:SIG1_3426 start
						//初期状態で「欠損歯」だった歯を、欠損歯で無くした場合に対応
						//歯牙状態が欠損歯でない、かつ、歯式に設定された状態コードが欠損歯(2)だった場合は、
						//状態コードを"0"に設定する
						//tmpArray.push(val.shiban + val.status + val.part);
						if ( val.part == "0"){
							tmpArray.push(val.shiban + (val.status == "2" ? 0 : val.status ) + val.part);
						} else {
							tmpArray.push(val.shiban + val.status + val.part);
						}
						// 故障対応:SIG1_3426 end
					}
				})
				// 故障対応:SIG1_3130 end
			}
		});
		
		//全ての配列を連結
		return  leftTopArray.concat(rightTopArray, leftBottomArray,rightBottomArray );

	};
		
	
	//歯式データを読み込み、歯式表示を構成します
	function bindData(data){
		
		//表示対象の歯式
		var shishikiArray = new Array();
		
		//データが配列の場合はそのまま
		//それ以外はカンマ区切り文字列として扱う
		if($.isArray(data)){
			shishikiArray = data;
		}else{
			//文字列を6桁で区切って配列に変換する
			for(i = 0; i < data.length ; i = i + 6){
				shishikiArray.push(data.substr(i, 6));
			}
		}


		$.each(shishikiArray, 
			function(i, val){
				addByShishiki(val);
			});
			
			//サイズ自動調整
			adjustImage();
	};
	
	function createShishiki(area, no, status, type, part){
		return AREA_TO_SHISHIKI_MAP[area][type] + no + status + part;
	}
	
	function createBui(shishiki){
	
		//番号は4バイト目
		var _no = shishiki.substr(3,1);
		//状態は5バイト目
		var _status = shishiki.length > 5 ? shishiki.substr(4,1) : "0";
		//部分コードが6バイト目
		var _part = shishiki.length > 5 ? shishiki.substr(5,1) : "0";
		
		var _area = '';
		var _type = '';
		
		//歯式の先頭3バイトから、位置情報と歯種別を特定する
		var _areaTmp = shishiki.substr(0,3);
		
		//パフォーマンス改善改修 start
		//変換テーブルをループでまわすのは効率が悪い
		//専用のテーブルを作って、そこから取得するように修正
		
		//変換テーブルを舐める
//		$.each(AREA_TO_SHISHIKI_MAP, 
//			function(i, val1){
//				$.each(val1, 
//					function(j, val2){
//						if(val2 == _areaTmp){
//							_area = i;
//							_type = j;
//							return false;
//						}
//					}
//				);
//			}
//		);

		var areaInfo = SHISHIKI_TO_AREA_MAP[_areaTmp];
		
		_area = areaInfo.area;
		_type = areaInfo.type;
		
		//パフォーマンス改善改修 end
		
		//画面上のインデックスに変換する
		var _index;
		
		switch(_area){
			case AREA_CODE.RIGHT_TOP:
			 	_index = 7 + parseInt(_no);
				break;
			
			case AREA_CODE.LEFT_TOP:
				_index = 8 - parseInt(_no);
				break;
				
			case AREA_CODE.LEFT_BOTTOM:
				_index = 24 - parseInt(_no);
				break;
			
			case AREA_CODE.RIGHT_BOTTOM:
				_index = 23 + parseInt(_no);
				break;
		}
		
		
		return {area:_area, no:_no, status:_status, type:_type, part:_part, index:_index};
	}
	
	//指定した箇所の部位情報を取得する
	function getBuiInfo(li){
		
		var buiArray = new Array();
		var shishiki = $.data(li.get(0), SHISHIKI_DATA_NAME);
		
		$.each(shishiki, function(i, val){
			buiArray.push(createBui(val));
		})
		
		return buiArray;
	}

	//------------------------------------------------------
	//イベント定義
	//------------------------------------------------------
	
	//パフォーマンス改善改修 start
	//編集モードの場合はイベントをバインド
	if(!options.readOnly){
		$(targetDiv).bind("buiSelect", f2.closure(function(event, index, status, type, part, option){
	
			select($lis.eq(index), status, type, part, option);
			
			if(options.autoAdjust){
					adjustImage();
			}
		})).bind("buiUnSelect", f2.closure(function(event, index){
			unSelect($lis.eq(index));
			
			if(options.autoAdjust){
					adjustImage();
			}
		})).bind("buiUnSelectAll", f2.closure(function(){
			$lis.each(function(){
				unSelect($(this));
			});
		})).bind("buiToggleSelect", f2.closure(function(event, index, status, type, part){
			toggleSelect($lis.eq(index), status, type, part);
			
			if(options.autoAdjust){
				adjustImage();
			}
		})).bind("buiUpdate", f2.closure(function(event, index, status, type, part){
			update($lis.eq(index), status, type, part);
			if(options.autoAdjust){
				adjustImage();
			}
		})).bind("buiBatchSelect", f2.closure(function(event, indexArray, type, status){
			batchSelect(indexArray, type, status);
			if(options.autoAdjust){
				adjustImage();
			}
		})).bind("buiInsert", f2.closure(function(event, index, status, type, part){
			add($lis.eq(index), status, type, part);
			if(options.autoAdjust){
				adjustImage();
			}
		})).bind("buiAddShishiki", f2.closure(function(event, shishiki){
			addByShishiki(shishiki);
			if(options.autoAdjust){
				adjustImage();
			}
		})).bind("buiResetStatus", f2.closure(function(event, status){
			resetStatus(status);
			if(options.autoAdjust){
				adjustImage();
			}
		})).bind("buiAddClassShishiki", f2.closure(function(event, shishiki, name){
			addClassByShishiki(shishiki, name);
		})).bind("buiSetShiga", f2.closure(function(event, index, type, shiga){
			setShiga($lis.eq(index), type, shiga);
		})).bind("buiUnSetShiga", f2.closure(function(event, index, type){
			setShiga($lis.eq(index), type, "0");
		})).bind("buiSeliarize", f2.closure(function(event, data){
			$.extend(data,seliarize());
		})).bind("buiBindData", f2.closure(function(event, data){
			bindData(data);
		})).bind("buiSetBuMode", f2.closure(function(event, index, type){
			setBuMode();
		})).bind("buiUnsetBuMode", f2.closure(function(event, index, type){
			unsetBuMode();
		})).bind("buiGetBuiInfo", f2.closure(function(event, index, info){
			$.extend(info,getBuiInfo($lis.eq(index)));
		})).bind("buiAdjustImage", f2.closure(function(event){
			adjustImage();
		}));
	}
};
})(jQuery);